package com.caregiver.watch.business.file.service;

import com.caregiver.watch.business.file.config.FileProperties;
import com.caregiver.watch.business.file.exception.FileUploadException;
import com.caregiver.watch.business.file.model.dto.UploadResponse;
import com.caregiver.watch.business.file.utils.FileTypeValidatorUtils;
import com.caregiver.watch.business.user.utils.UserInfoUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.UUID;

import static com.caregiver.watch.common.constant.Constants.DOT;
import static com.caregiver.watch.common.constant.Constants.SLASH;
import static com.caregiver.watch.common.constant.Constants.UNDERLINE;

@Slf4j
@Service
public class FileStorageServiceImpl implements FileStorageService {


    private static final DateTimeFormatter FILE_NAME_DATE_FORMATTER = DateTimeFormatter.ofPattern("yyyyMMddHHmmss");
    private static final int UUID_SHORT_LENGTH = 8;

    private final String imageLocation;
    private final String audioLocation;

    private final FileProperties fileProperties;

    public FileStorageServiceImpl(FileProperties fileProperties) {
        this.fileProperties = fileProperties;
        this.imageLocation = fileProperties.getUploadImagesPath();
        this.audioLocation = fileProperties.getUploadAudiosPath();
    }

    @Override
    public UploadResponse storeImage(MultipartFile file) {
        if (FileTypeValidatorUtils.isImage(file)) {
            // 获取用户ID
            Long userId = UserInfoUtils.getUserId();
            String fileName = storeFile(file, Paths.get(imageLocation, String.valueOf(userId)), "img_");
            String fileDownloadUri = fileProperties.getUrl() + ensureUriFormat(fileProperties.getDownloadImagesPath(), String.valueOf(userId)) + fileName;
            return new UploadResponse(fileName, fileDownloadUri, file.getContentType(), file.getSize());
        }
        throw new FileUploadException("不支持的文件类型，请上传图片文件");
    }


    /**
     * 确保uri格式正确
     *
     * @param uri
     * @return
     */
    private String ensureUriFormat(String uri, String... more) {
        if (StringUtils.isBlank(uri)) {
            return uri;
        }
        // 确保以"/"开头
        if (!uri.startsWith(SLASH)) {
            uri = SLASH + uri;
        }
        // 确保以指定后缀结尾
        if (!uri.endsWith(SLASH)) {
            uri = uri + SLASH;
        }
        if (ArrayUtils.isEmpty(more)) {
            return uri;
        }
        for (String s : more) {
            uri = uri + s + SLASH;
        }
        return uri;
    }

    @Override
    public UploadResponse storeAudio(MultipartFile file) {
        if (FileTypeValidatorUtils.isAudio(file)) {
            // 获取用户ID
            Long userId = UserInfoUtils.getUserId();
            String fileName = storeFile(file, Paths.get(audioLocation, String.valueOf(userId)), "audio_");
            String fileDownloadUri = fileProperties.getUrl() + ensureUriFormat(fileProperties.getDownloadAudiosPath(), String.valueOf(userId)) + fileName;
            return new UploadResponse(fileName, fileDownloadUri, file.getContentType(), file.getSize());
        }
        throw new FileUploadException("不支持的文件类型，请上传音频文件");
    }

    private String storeFile(MultipartFile file, Path location, String prefix) {
        try {
            if (file.isEmpty()) {
                throw new FileUploadException("文件为空");
            }
            // 判断 Path 是否存在 如果不存在 需要重新创建
            if (!Files.exists(location)) {
                Files.createDirectories(location);
            }
            // 生成唯一文件名
            String originalFileName = file.getOriginalFilename();
            String fileExtension = StringUtils.EMPTY;
            if (originalFileName != null && originalFileName.lastIndexOf(DOT) > 0) {
                fileExtension = originalFileName.substring(originalFileName.lastIndexOf(DOT));
            }

            String fileName = prefix +
                    LocalDateTime.now().format(FILE_NAME_DATE_FORMATTER) +
                    UNDERLINE + UUID.randomUUID().toString().substring(0, UUID_SHORT_LENGTH) +
                    fileExtension;

            Path targetLocation = location.resolve(fileName);
            try (InputStream inputStream = file.getInputStream()) {
                Files.copy(inputStream, targetLocation, StandardCopyOption.REPLACE_EXISTING);
            }
            return fileName;
        } catch (IOException e) {
            throw new FileUploadException("文件存储失败: " + file.getOriginalFilename(), e);
        }
    }
}